#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h> 
#include <stdlib.h>       
#include <string.h>
#include <pthread.h>
//#include <sys/sem.h>
#include <errno.h>
#include <sys/ipc.h>
//#include <sys/msg.h>
#include <sys/timeb.h>
#include <sys/socket.h>
//#include <sys/socketvar.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <semaphore.h>
#include <string.h>
#include <termios.h>
#include <linux/input.h>
#include <semaphore.h>
#include <linux/shm.h>
#include <asm/unistd.h>

#include "common.h"

#define HEART_BEAT_MAX_TIME 5
#define PUSHING_AUDIO_STATUS_TIME	2

//protoSlaveType
enum _protoSlaveType
{
		_askForPush				 			= 	0x00,
		_onLineHeartBeat			 	= 	0x01,
		_stopPush								= 	0x02,
		_sendOneFrameData				=		0x03,
};

typedef struct _contrlData
{
		pthread_mutex_t Lock;
		unsigned int serviceNumber;
		struct sockaddr_in clientAddr;
		unsigned int clientLastHeartBeatTime;
}ContrlData;
static ContrlData *pContrlData = NULL;

static sem_t sem_pushing;

extern SystemParam* pgSystemParam;

static int askForPush(struct recvData *recvData, struct packageFilter *pFilter);
static int onLineHeartBeat(struct recvData *recvData, struct packageFilter *pFilter);
static int stopPush(struct recvData *recvData, struct packageFilter *pFilter);
static int sendOneFrameData(struct recvData *recvData, struct packageFilter *pFilter);

static void* checkClientHeartBeatThread(void *arg);
static void* checkPushingStatusThread(void *arg);

int initPushAudioServer()
{
		pContrlData = (ContrlData*)malloc(sizeof(ContrlData));
		if(pContrlData == NULL)
		{
				printf("pContrlData == NULL ! {%s(%d)}\n",__FILE__,__LINE__);
				return -1;	
		}
		
		memset(pContrlData, 0, sizeof(ContrlData));
		pContrlData->serviceNumber = 0;
		pContrlData->clientAddr.sin_family = AF_INET;
		
		if( pthread_mutex_init (&(pContrlData->Lock),NULL) != 0   ) 
		{
				printf("pthread_mutex_init failure {%s(%d)}\n",__FILE__,__LINE__);	
				free(pContrlData);
				pContrlData = NULL;
				return -2;
		}	
		
		if( sem_init(&(sem_pushing), 1, 0) != 0   ) 
		{
				printf("sem_init failure {%s(%d)}\n",__FILE__,__LINE__);	
				return -3;
		}	
	
		pthread_t ptID;	
		if( pthread_create(&ptID, NULL, checkClientHeartBeatThread, (void *)0) != 0 )
		{
				printf("create thread failure {%s(%d)}\n",__FILE__,__LINE__);		
				return -4;
		}  
		
		if( pthread_create(&ptID, NULL, checkPushingStatusThread, (void *)0) != 0 )
		{
				printf("create thread failure {%s(%d)}\n",__FILE__,__LINE__);		
				return -5;
		} 
		
		system("rm -rf /sdcard/1.aac");
		return 0;
}

void pushAudioServer(struct recvData *recvData)
{								
		if(recvData == NULL)
		{
				printf("recvData == NULL ! {%s(%d)}\n",__FILE__,__LINE__);
				return;	
		}
	
		if(pContrlData == NULL)
		{
				printf("pContrlData == NULL ! {%s(%d)}\n",__FILE__,__LINE__);
				return;	
		}
		
		struct packageFilter filter;
		int ret = explainPackageHead(recvData, &filter);
		if(ret < 0)
		{
				return;	
		}
		
		switch(filter.protoSlaveType)
		{
				case _askForPush:
				{
						askForPush(recvData, &filter);
						break;	
				}
				case _onLineHeartBeat:
				{
						onLineHeartBeat(recvData, &filter);
						break;
				}
				case _stopPush:
				{
						stopPush(recvData, &filter);
						break;	
				}
				case _sendOneFrameData:
				{
						sendOneFrameData(recvData, &filter);
						break;
				}
				default:
				{
						printf("filter.protoSlaveType not right !  filter.protoSlaveType = %d\n", filter.protoSlaveType);
						break;	
				}
		}
}


static int askForPush(struct recvData *recvData, struct packageFilter *pFilter)
{
		if(pFilter->dataDirection != 0x00)	
		{
				printf("proto %d,%d pFilter->dataDirection error ! pFilter->dataDirection = %d {%s,%d}\n", pFilter->protoMasterType, pFilter->protoSlaveType, pFilter->dataDirection, __FILE__, __LINE__);
				printf("recvData->buf[3], buf[4] = %d,%d\n", recvData->buf[3], recvData->buf[4]);
				return -1;	
		}
		
		if(pFilter->dataLen != 5)
		{
				printf("proto %d,%d pFilter->dataLen error ! pFilter->dataLen = %d\n", pFilter->protoMasterType, pFilter->protoSlaveType, pFilter->dataLen);
				return -2;	
		}
		
		unsigned char audioType = pFilter->pData[0];
		unsigned char privateData[4];
		memcpy(privateData, pFilter->pData + 1, 4);
		unsigned char returnRet;
		unsigned int serviceNumber;
		
		pthread_mutex_lock (&(pContrlData->Lock));
		if(pContrlData->clientAddr.sin_addr.s_addr == 0 || pContrlData->clientAddr.sin_addr.s_addr == recvData->addr.sin_addr.s_addr)
		{
				pContrlData->serviceNumber ++;
				pContrlData->clientLastHeartBeatTime = time(NULL);
				pContrlData->clientAddr.sin_addr.s_addr = recvData->addr.sin_addr.s_addr;
				pContrlData->clientAddr.sin_port = recvData->addr.sin_port;
				
				returnRet = 0;
				serviceNumber = pContrlData->serviceNumber;
				
				printf("audio ask for push success ! serviceNumber=%d\n", serviceNumber);
				printf("audio pContrlData->clientAddr.sin_addr.s_addr, pContrlData->clientAddr.sin_port=%d,%d\n", pContrlData->clientAddr.sin_addr.s_addr, pContrlData->clientAddr.sin_port);
				printf("audio recvData->addr.sin_addr.s_addr, recvData->addr.sin_port=%d,%d\n", recvData->addr.sin_addr.s_addr, recvData->addr.sin_port);
		}
		else
		{
				printf("audio ask for push fail ! serviceNumber=%d\n", serviceNumber);
				printf("audio pContrlData->clientAddr.sin_addr.s_addr, pContrlData->clientAddr.sin_port=%d,%d\n", pContrlData->clientAddr.sin_addr.s_addr, pContrlData->clientAddr.sin_port);
				printf("audio recvData->addr.sin_addr.s_addr, recvData->addr.sin_port=%d,%d\n", recvData->addr.sin_addr.s_addr, recvData->addr.sin_port);
				returnRet = 1;	
				serviceNumber = pContrlData->serviceNumber;
		}
		pthread_mutex_unlock (&(pContrlData->Lock));
		
		unsigned char dataDirection = 0x01;
		unsigned short dataLen = 10;
		unsigned int headLen = recvData->count - pFilter->dataLen;
		unsigned int packageSize = headLen + dataLen;
		createProtoCombinationData(recvData->buf + 3, pFilter->deviceType, dataDirection, pFilter->communicationWay, dataLen);
		
		unsigned char checkCode = 0;
		for(unsigned char i=0; i < headLen-1; i++)
		{
				checkCode += recvData->buf[i];
		}
		recvData->buf[headLen - 1] = checkCode;
		
		recvData->buf[headLen] = audioType;
		recvData->buf[headLen + 1] = returnRet;
		memcpy(recvData->buf + headLen + 2, privateData, 4);
		changeUIntToByte(serviceNumber, recvData->buf + headLen + 6);
		
		MainSend(recvData->buf, packageSize, &(recvData->addr));
		
		pgSystemParam->pushingAudio = true;
		sem_post(&(sem_pushing));
		
		return 0;
}


static int onLineHeartBeat(struct recvData *recvData, struct packageFilter *pFilter)
{
		if(pFilter->dataDirection != 0x00)	
		{
				printf("proto %d,%d pFilter->dataDirection error ! pFilter->dataDirection = %d\n", pFilter->protoMasterType, pFilter->protoSlaveType, pFilter->dataDirection);
				return -1;	
		}
		
		if(pFilter->dataLen != 17)
		{
				printf("proto %d,%d pFilter->dataLen error ! pFilter->dataLen = %d\n", pFilter->protoMasterType, pFilter->protoSlaveType, pFilter->dataLen);
				return -2;	
		}
	
		if(&(recvData->addr) == NULL)
		{
				printf("recvData->addr == NULL !\n");
				return -3;	
		}
		
		int ret;
		unsigned char privateData[4];
		unsigned int serviceNumber;
		memcpy(privateData, pFilter->pData + 9, 4);
		changeByteToUInt(serviceNumber, pFilter->pData + 13);

		pthread_mutex_lock (&(pContrlData->Lock));
		if(pContrlData->serviceNumber != serviceNumber)
		{
				printf("audio onLineHeartBeat:serviceNumber not match ! pContrlData->serviceNumber=%d,serviceNumber=%d {%s,%d}\n",pContrlData->serviceNumber,serviceNumber,__FILE__,__LINE__);	
		}
		else if(pContrlData->clientAddr.sin_addr.s_addr != recvData->addr.sin_addr.s_addr)
		{
				printf("audio onLineHeartBeat:ipaddr not match ! saveAddr=%d,nowAddr=%d {%s,%d}\n",pContrlData->clientAddr.sin_addr.s_addr,recvData->addr.sin_addr.s_addr,__FILE__,__LINE__);	
		}
		else
		{
				pContrlData->clientLastHeartBeatTime = time(NULL);
				//printf("refresh heartBeat Time: time=%d\n", pContrlData->clientLastHeartBeatTime);
		}
		pthread_mutex_unlock (&(pContrlData->Lock));
		
		return 0;
		
}

static int stopPush(struct recvData *recvData, struct packageFilter *pFilter)
{
		if(pFilter->dataDirection != 0x00)	
		{
				printf("audio proto %d,%d pFilter->dataDirection error ! pFilter->dataDirection = %d\n", pFilter->protoMasterType, pFilter->protoSlaveType, pFilter->dataDirection);
				return -1;	
		}
		
		if(pFilter->dataLen != 17)
		{
				printf("audio proto %d,%d pFilter->dataLen error ! pFilter->dataLen = %d\n", pFilter->protoMasterType, pFilter->protoSlaveType, pFilter->dataLen);
				return -2;	
		}
	
		if(&(recvData->addr) == NULL)
		{
				printf("audio recvData->addr == NULL !\n");
				return -3;	
		}
		
		int ret;
		unsigned char privateData[4];
		unsigned int serviceNumber;
		memcpy(privateData, pFilter->pData + 9, 4);
		changeByteToUInt(serviceNumber, pFilter->pData + 13);

		pthread_mutex_lock (&(pContrlData->Lock));
		if(pContrlData->serviceNumber != serviceNumber)
		{
				printf("audio stopPush:serviceNumber not match ! pContrlData->serviceNumber=%d,serviceNumber=%d {%s,%d}\n",pContrlData->serviceNumber,serviceNumber,__FILE__,__LINE__);	
		}
		else if(pContrlData->clientAddr.sin_addr.s_addr != recvData->addr.sin_addr.s_addr)
		{
				printf("audio stopPush:ipaddr not match ! saveAddr=%d,nowAddr=%d {%s,%d}\n",pContrlData->clientAddr.sin_addr.s_addr,recvData->addr.sin_addr.s_addr,__FILE__,__LINE__);	
		}
		else
		{
				pContrlData->clientAddr.sin_addr.s_addr = 0;
				printf("audio clear pushVideo ipAddr\n");
		}
		pthread_mutex_unlock (&(pContrlData->Lock));
		
		pgSystemParam->pushingAudio = false;
		//printf("recv stopPush data success ! {%s,%d}\n", __FILE__,__LINE__);
		return 0;
}

static int sendOneFrameData(struct recvData *recvData, struct packageFilter *pFilter)
{
		if(pFilter->dataDirection != 0x00)	
		{
				printf("audio proto %d,%d pFilter->dataDirection error ! pFilter->dataDirection = %d\n", pFilter->protoMasterType, pFilter->protoSlaveType, pFilter->dataDirection);
				return -1;	
		}
		
		if(pFilter->dataLen < 17)
		{
				printf("audio proto %d,%d pFilter->dataLen error ! pFilter->dataLen = %d\n", pFilter->protoMasterType, pFilter->protoSlaveType, pFilter->dataLen);
				return -2;	
		}
	
		if(&(recvData->addr) == NULL)
		{
				printf("recvData->addr == NULL !\n");
				return -3;	
		}
		
		unsigned int serviceNumber;
		changeByteToUInt(serviceNumber, pFilter->pData);
		
		bool needDecode = false;
		pthread_mutex_lock (&(pContrlData->Lock));
		if(pContrlData->serviceNumber != serviceNumber)
		{
				//printf("sendOneFrameData:serviceNumber not match ! pContrlData->serviceNumber=%d,serviceNumber=%d {%s,%d}\n",pContrlData->serviceNumber,serviceNumber,__FILE__,__LINE__);	
		}
		else if(pContrlData->clientAddr.sin_addr.s_addr != recvData->addr.sin_addr.s_addr)
		{
				//printf("sendOneFrameData:ipaddr not match ! saveAddr=%d,nowAddr=%d {%s,%d}\n",pContrlData->clientAddr.sin_addr.s_addr,recvData->addr.sin_addr.s_addr,__FILE__,__LINE__);	
		}
		else
		{
				//printf("prepare to deal audio frame data ! recvData->count = %d\n", recvData->count);
				needDecode = true;
		}
		pthread_mutex_unlock (&(pContrlData->Lock));
		
		needDecode = true; //for test
		
		if(needDecode == true)
		{
				pushAudioData(pFilter->pData + 17, pFilter->dataLen - 17);
				/*
				pgSystemParam->pushingAudio = true;
				sem_post(&sem_pushing);
				int ret = PushBlockInfoData(&(pgSystemParam->aacPushBlock),pFilter->pData + 17, pFilter->dataLen - 17);	
				if(ret < 0)
				{
						writeLog("pgSystemParam->aacPushBlock is full !\n", __FILE__, __LINE__);	
				}
				else
				{
						//writeLog("push block pgSystemParam->aacPushBlock success !\n", __FILE__, __LINE__);	
				}
				
				char name[222];
				FILE *fout=NULL;
				sprintf(name,"/sdcard/1.aac");
				if(fout==NULL) fout = fopen(name, "ab");
			  if(fout)fwrite(pFilter->pData + 17, pFilter->dataLen - 17, 1, fout);
			  if(fout)fclose(fout);*/
		}
}

static void* checkClientHeartBeatThread(void *arg)
{
		struct timespec ts;
		struct timeval  tv;	
		static sem_t sem_tmp;
		if( sem_init(&(sem_tmp), 1, 0) != 0   ) 
		{
				printf("sem_init failure {%s(%d)}\n",__FILE__,__LINE__);	
				return NULL;
		}	
		
		while( !IsExit() )
		{
				gettimeofday(&tv, NULL); 
				
			  ts.tv_sec  = tv.tv_sec + HEART_BEAT_MAX_TIME;
		    ts.tv_nsec = tv.tv_usec + 0 * 1000 * 1000;		
		    
		    sem_timedwait(&(sem_tmp),&ts);
		    
		    //printf("into checkClientHeartBeatThread !");
		    
		    time_t nowTime = time(NULL);
		    pthread_mutex_lock (&(pContrlData->Lock));  
				if(pContrlData->clientAddr.sin_addr.s_addr != 0)
				{
						if(nowTime - pContrlData->clientLastHeartBeatTime > HEART_BEAT_MAX_TIME)
						{
								printf("audio clear client info ! nowTime=%ld, clientLastHeartBeatTime=%d {%s,%d}\n", nowTime,pContrlData->clientLastHeartBeatTime, __FILE__, __LINE__);
								printf("audio pContrlData->clientAddr.sin_addr.s_addr = %d\n", pContrlData->clientAddr.sin_addr.s_addr);
								pContrlData->clientAddr.sin_addr.s_addr = 0;
						}
				}
				pthread_mutex_unlock (&(pContrlData->Lock));
		}
}

static void* checkPushingStatusThread(void *arg)
{
		struct timespec ts;
		struct timeval  tv;	
		
		while( !IsExit() )
		{
				gettimeofday(&tv, NULL); 
				
			  ts.tv_sec  = tv.tv_sec + PUSHING_AUDIO_STATUS_TIME;
		    ts.tv_nsec = tv.tv_usec + 0 * 1000 * 1000;		
		    
		    sem_timedwait(&(sem_pushing),&ts);
		    
		    if(pgSystemParam->pushingAudio == true)
		    {
		    		//writeLog("clear pgSystemParam->pushingAudio status\n", __FILE__, __LINE__);
		    }
		    
		   	pgSystemParam->pushingAudio = false;
		}
	
}